﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
using XPressify.Data.Helpers;

namespace XPressify.Data.CompliedQueries
{
    public class UserCompiledQueries
    {
        public static Func<Repository, Guid, IEnumerable<User>> GetAllFriends
        {
            get
            {
                return CompiledQuery.Compile<Repository, Guid, IEnumerable<User>>(
                    (context, userId) => context.BaseObjects.OfType<Relationship>().Where(
                        rel =>
                        rel.BaseSubjectId == userId && rel.RelationType == RelationshipType.FriendOf &&
                        rel.Status == RelationshipStatus.Confirmed).Select(rel => rel.BaseSubject2).OfType<User>().Union
                                             (
                                                 context.BaseObjects.OfType<Relationship>().Where(
                                                     rel =>
                                                     rel.BaseSubjectId2 == userId &&
                                                     rel.RelationType == RelationshipType.FriendOf &&
                                                     rel.Status == RelationshipStatus.Confirmed).Select(
                                                         rel => rel.BaseSubject).OfType<User>())
                    );
            }
        }

        public static Func<Repository, Guid, User> GetAdmin
        {
            get
            {
                return CompiledQuery.Compile<Repository, Guid, User>(
                    (context, userId) => context.BaseObjects.OfType<Relationship>().Where(
                        rel =>
                        rel.BaseSubjectId2 == userId && rel.RelationType == RelationshipType.AdministratorOf &&
                        rel.Status == RelationshipStatus.Confirmed).Select(
                            rel => rel.BaseSubject).OfType<User>().SingleOrDefault()
                    );
            }
        }

        public static Func<Repository, Guid, IEnumerable<User>> GetMembersOf
        {
            get
            {
                return CompiledQuery.Compile<Repository, Guid, IEnumerable<User>>(
                    (context, userId) => context.BaseObjects.OfType<Relationship>().Where(
                        rel =>
                        rel.BaseSubjectId2 == userId && rel.RelationType == RelationshipType.MemberOf &&
                        rel.Status == RelationshipStatus.Confirmed).Select(
                            rel => rel.BaseSubject).OfType<User>()
                    );
            }
        }

        public static Func<Repository, Guid, IEnumerable<User>> GetMembersOfOrderByName
        {
            get
            {
                return CompiledQuery.Compile<Repository, Guid, IEnumerable<User>>(
                    (context, userId) => context.BaseObjects.OfType<Relationship>().Where(
                        rel =>
                        rel.BaseSubjectId2 == userId && rel.RelationType == RelationshipType.MemberOf &&
                        rel.Status == RelationshipStatus.Confirmed).Select(
                            rel => rel.BaseSubject).OfType<User>().OrderBy(usr => usr.FirstName).ThenBy(
                                usr => usr.LastName)
                    );
            }
        }

        public static Func<Repository, Guid, User> GetUser
        {
            get
            {
                return CompiledQuery.Compile<Repository, Guid, User>(
                    (context, userId) => context.BaseSubjects.OfType<User>().SingleOrDefault(usr => usr.Id == userId)
                    );
            }
        }

        public static Func<Repository, string, User> GetUserByEmail
        {
            get
            {
                return CompiledQuery.Compile<Repository, string, User>(
                    (context, email) => context.BaseSubjects.OfType<User>().SingleOrDefault(usr => usr.Email == email)
                    );
            }
        }

        public static Func<Repository, Guid, BaseSubject> GetSubjectFromRelationship
        {
            get
            {
                return CompiledQuery.Compile<Repository, Guid, BaseSubject>(
                    (context, relationshipId) =>
                    context.BaseObjects.OfType<Relationship>().FirstOrDefault(x => x.Id == relationshipId).BaseSubject
                    );
            }
        }

        public static Func<Repository, Guid, BaseSubject> GetSubject2FromRelationship
        {
            get
            {
                return CompiledQuery.Compile<Repository, Guid, BaseSubject>(
                    (context, relationshipId) =>
                    context.BaseObjects.OfType<Relationship>().FirstOrDefault(x => x.Id == relationshipId).BaseSubject2
                    );
            }
        }

        public static Func<Repository, Guid, IEnumerable<Guid>> UsersAlreadyRequested
        {
            get
            {
                return CompiledQuery.Compile<Repository, Guid, IEnumerable<Guid>>(
                    (context, subjectId) =>
                    context.BaseObjects.OfType<Relationship>().Where(
                        rel => rel.RelationType == RelationshipType.MemberOf && rel.BaseSubject2.Id == subjectId).
                        Select(rel => rel.BaseSubject).OfType<User>().Select(x => x.Id)
                    );
            }
        }

    }
}